#-*- coding: utf-8 -*-

#This file is part of pyLot library.
#
# pyLot is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pyLot is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with pyLot.  If not, see <http://www.gnu.org/licenses/>.

__author__ = u'Pierre Puiseux, Guillaume Baty'
__copyright__ = u"Copyright 2011-2012 (C) andheo, Université de Pau et des Pays de l'Adour"
__credits__ = [u'Pierre Puiseux', u'Guillaume Baty']
__license__ = "GNU Lesser General Public License"

__all__ = []

import numpy

from scimath.units.unit import unit, dimensionless
from scimath.units.convert import convert
from traits.api import Tuple, HasTraits, Float, Unicode

from pyLot.core import ENCODING

class BaseQuantity(HasTraits):
  value = Float()
  name = Unicode(u'')

  def _getData(self):
    raise NotImplementedError

  def _getSymbol(self):
    raise NotImplementedError

  data = property(fget=_getData)
  symbol = property(fget=_getSymbol)

  def toValue(self, to_unit):
    raise NotImplementedError

  def toUnicode(self, to_unit):
    raise NotImplementedError
#pq.UnitQuantity(name, definition=None, symbol=None, u_symbol=None,
#                aliases=[], doc=None)
#Pa = pq.UnitQuantity('pascal', pq.N / pq.m ** 2, symbol='Pa', 
#                     aliases=['pascals'])


class ScimathQuantity(BaseQuantity):
  u"""
  Trait class for units using scimath.units package
  """
  derivation = Tuple()

  def _setData(self, unit_obj):
    self.derivation = unit_obj.derivation
    self.value = unit_obj.value
    if unit_obj.label :
      self.label = unit_obj.label.decode(ENCODING)
    else :
      self.label = u''

  def getData(self):
    u = unit(self.value, self.derivation)
    u.label = self.label
    return u

  data = property(fget=getData)

  def __init__(self, unit_obj, **traits):
    super(ScimathQuantity, self).__init__(**traits)
    if isinstance(unit_obj, unit) :
      pass
    else :
      unit_obj = unit(unit_obj, dimensionless.derivation)

    self._setData(unit_obj)

  # TODO: I don't think these will work for derived classes...
  def __neg__(self):
    return self.__class__(-self.data, name=self.name)

  def __abs__(self):
    name = '|%s|' % self.name if self.name else ''
    return self.__class__(abs(self.data), name=name)

  def __add__(self, other):
    return self.__class__(self.data + other.data, name=self.name)

  def __sub__(self, other):
    return self.__class__(self.data - other.data, name=self.name)

  def __mul__(self, other):
    return self.__class__(self.data * other.data)

  def __div__(self, other):
    return self.__class__(self.data / other.data)

  def __pow__(self, other):
    return self.__class__(self.data ** other)

  def __repr__(self):
    """ Return the string representation of this quantity. """
    if isinstance(self.data, numpy.ndarray):
      data_repr = '<array>'
    else:
      data_repr = self.data
    return '%s(name=%s, data=%s)' % \
          (self.__class__.__name__,
           self.name, data_repr)

  def toValue(self, to_unit):
    return convert(self.value, self.data, to_unit)

  def toUnicode(self, to_unit):
    return u'%s %s' % (self.toValue(to_unit), to_unit.label)


if __name__ == '__main__' :
  pass
